home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_100
/
123_01
/
pp.c
< prev
next >
Wrap
Text File
|
1985-03-09
|
14KB
|
642 lines
/*******************************************************\
** A preprocessor using the "C" syntax **
** described by K&R in "The C Programming **
** Language." Based on the macro processor **
** in Ratfor from K&P's "Software Tools." **
** **
** Robert T Pasky **
** 36 Wiswall Rd **
** Newton Centre, MA 02159 **
** (617) 964-3641 **
\*******************************************************/
/*
** format is:
** pp <infile> [<outfile>] [-d]\n");
**
** if <outfile> is not given, output will be placed in
** <infile>.PP.
** The optional -d turns on the debug mode which is only
** useful if you want to watch what goes on inside the
** program as it crunches files.
**
** This version is not simply a translation from the
** Ratfor version: it was modified to conform to the
** "official" format of the C preprocessor as defined
** in the K&R C Programming Language book.
** The output file can be fed into the BDS C compiler;
** or any other compiler (and other languages?) for
** which the input was intended.
**
** This program has #include file capability and
** symbolic parameter substitution. That means you
** can write something like:
** #define max(a,b) (a) > (b) ? (a) : (b)
** which will replace:
** max(x+1,y-1)
** with:
** (x+1) > (y-1) ? (x+1) : (y-1)
**
** Here "max(a,b)" is a template with two parameters:
** a and b. When the preprocessor sees "max(x+1,y-1)"
** it replaces the first parameter (a) in the definition
** with "x+1" and the second parameter ("b") with "y-1".
** Notice that the "(" must follow "max" with no intervening
** spaces. That's so the preprocessor can differentiate
** between argumented and non-argumented macros, e.g.,
** "#define ERROR (-1)".
** Secondly, the a and b in the definition are surrounded
** by parentheses. This is often a good idea; it avoids
** problems that might occur with precedence rules, e.g.:
** #define div(a,b) a/b
** ... div(x+2,5)
** would result in "x+2/5" which is interpreted as x+(2/5)
** instead of the intended "(x+2)/5".
**
** Note: this program has NOT been rigorously tested
** and, as provided here, is quite limited in its array
** size (it's easy enough to increase the defines for
** the array sizes if you have lots of memory).
** The proportions allocated among the various arrays
** may also need tuning. For example, if you like to use
** lots of short define strings you might increase MAXTOK
** and MAXDEF. On the other hand, if you have relatively
** few defines but they tend to be long-winded, you could
** shorten these in favor of increasing MAXTBL (and
** possibly DEFSIZ).
*/
#include "bdscio.h"
#define STDOUT 1
#define STDERR 1 /* EKR 3/10/83 */
#define YES 1 /* EKR 3/10/83 */
#define NO 0 /* EKR 3/10/83 */
#define NUL NULL /* EKR 3/10/83 */
#define EQUAL 0 /* EKR 3/10/83 */
#define ALPHA 'a'
#define LETTER 'a'
#define DIGIT '9'
#define LPAREN '('
#define RPAREN ')'
#define LBRACK '('
#define RBRACK ')'
#define COMMA ','
#define ARGFLAG 0xFA
#define HASH '#'
#define DEFTYPE 0xFC
#define INCTYPE 0xFB
#define MAXFILNAME 20
#define CHARBUFSIZE 80
#define MAXDEF 600
#define MAXTOK 200
#define MAXTBL 1000
#define MAXPTR 600
#define DEFSIZ 129
#define TOKSIZ 129
#define EVALSIZE 200
#define ARGSIZE 200
#define CALLSIZE 200
int bp;
char buf[CHARBUFSIZE];
char inbuf[BUFSIZ], incbuf[BUFSIZ], outbuf[BUFSIZ];
char outfile[MAXFILNAME], incfil[MAXFILNAME];
char defn[MAXDEF], token[MAXTOK], table[MAXTBL];
int namptr[MAXPTR];
int lastp, lastt;
int cp, ep;
char evalst[EVALSIZE];
int ap, argstk[ARGSIZE], callst[CALLSIZE];
int nlb, plev[CALLSIZE];
int incflg;
int debug;
main(argc, argv)
int argc;
char **argv;
{
/*
** macro - expand macros with arguments
*/
char t, *defnam, *incnam, *s;
int deftyp[2];
char *balp;
debug = FALSE;
deftyp[0] = DEFTYPE;
deftyp[1] = NUL;
defnam = "#define";
incnam = "#include";
incflg = NO;
balp = "()";
bp = -1;
lastp = lastt = -1;
printf("pp v1.0\n");
if (argc < 2)
perr("usage: pp <infile> [<outfile>] [-d]\n");
s = *++argv;
if (fopen(s, inbuf) == ERROR)
perr1("cannot open <%s>", s);
argc -= 2; argv++;
if (argc > 0 && **argv != '-') {
strcpy (outfile, s = *argv++);
argc--;
}
else {
strcpy (outfile, s);
strcat (outfile, ".PP");
}
if (fcreat(outfile, outbuf) == ERROR)
perr1("cannot create <%s>", outfile);
fprintf(STDERR, "output will be in <%s>\n", outfile);
while (argc-- > 0) {
s = *argv++;
if (strcmp(s, "-D") == EQUAL)
debug = TRUE;
}
if (debug) fprintf(STDERR,"debug is on\n");
instal(defnam, deftyp);
deftyp[0] = INCTYPE;
instal(incnam, deftyp);
cp = -1;
ap = ep = 0;
for (t = gettok(); t != CPMEOF; t = gettok()) {
if (t == ALPHA) {
if (lookup(token, defn) == NO)
puttok(token);
else {
if (*defn == INCTYPE) {
doinc();
continue;
}
if (++cp > CALLSIZE)
perr("call stack overflow\n");
callst[cp] = ap;
ap = push(ep, argstk, ap);
puttok(defn);
putchr(NUL);
if (debug) fprintf(STDERR, "push defn: <%s>\n", defn);
ap = push(ep, argstk, ap);
/*********************/
if (*defn == DEFTYPE)
while (isspace(gettok()))
;
/*********************/
puttok(token);
putchr(NUL);
if (debug) fprintf(STDERR, "push name: <%s>\n", token);
ap = push(ep, argstk, ap);
t = gettok();
pbstr(token);
if (debug) fprintf(STDERR, "next token: <%s>\n", token);
if (t != LPAREN)
pbstr(balp); /* add () if none */
plev[cp] = 0;
}
}
else if (cp == -1)
puttok(token);
/* else if (t == LBRACK) {
** nlb = 1;
** while (1) {
** t = gettok();
** if (t == LBRACK)
** nlb++;
** else if (t == RBRACK) {
** nlb--;
** if (nlb == 0)
** break;
** }
** else if (t == CPMEOF)
** perr("EOF in string\n");
** puttok(token);
** }
** }
*/
else if (t == LPAREN) {
if (plev[cp]++ > 0)
puttok(token);
}
else if (t == RPAREN) {
if (--plev[cp] > 0)
puttok(token);
else {
putchr(NUL);
eval(argstk, callst[cp], ap - 1);
ap = callst[cp]; /* pop eval stack */
ep = argstk[ap];
cp--;
}
}
else if (t == COMMA && plev[cp] == 1) {
putchr(NUL);
ap = push(ep, argstk, ap);
}
else
puttok(token);
}
if (cp != -1)
perr("unexpected EOF (not at level 0)\n");
putc(CPMEOF, outbuf);
fflush(outbuf);
fclose(outbuf);
exit();
}
perr(s)
char *s;
{
fprintf(STDERR, s);
exit();
}
perr1(s, t)
char *s, *t;
{
fprintf(STDERR, s, t);
exit();
}
/*
** lookup - locate name, extract def. from table
*/
lookup(name, defn)
char name[], defn[];
{
int i, j, k;
if(debug) fprintf(STDERR, "lookup: name <%s>...", name);
for (i = lastp; i >= 0; i--) {
if(debug) fprintf(STDERR, "\nnamptr: %d table: <%s>",
namptr[i], &table[namptr[i]]);
if (strcmp(&table[namptr[i]], name) == EQUAL) {
j = strlen(name) + 1;
strcpy (defn, &table[namptr[i] + j]);
if(debug) fprintf(STDERR, "found! defn: <%s>\n", defn);
return(YES);
}
}
if(debug) fprintf(STDERR, "not found.\n");
return(NO);
}
/*
** instal - add name and definition to table
*/
instal(name, defn)
char name[], defn[];
{
int dlen, nlen;
if(debug) fprintf(STDERR, "instal: name <%s> defn <%s>\n", name, defn);
nlen = strlen(name) + 1;
dlen = strlen(defn) + 1;
if (lastt + nlen + dlen > MAXTBL || lastp >= MAXPTR)
fprintf(STDERR, "<%s>: too many defns\n", name);
namptr[++lastp] = lastt + 1;
strcpy(&table[lastt + 1], name);
strcpy(&table[lastt + nlen + 1], defn);
lastt += nlen + dlen;
}
/*
** getdef - for no arguments - get name and definition
*/
getdef(token, defn)
char token[], defn[];
{
int i, nlpar;
char c;
if(debug) fprintf(STDERR, "getdef: token <%s>\n", token);
if ((c = ngetc()) != LPAREN)
perr("missing left paren\n");
else if (gettok() != ALPHA)
perr("non-alphanumeric token\n");
else if ((c = ngetc()) != COMMA)
perr("missing comma in